package com.iwhalecloud.citybrain.flow.platform.manager.infrastructure.services.impl;

import com.iwhalecloud.citybrain.flow.platform.manager.application.service.NodeCandidateService;
import com.iwhalecloud.citybrain.flow.platform.manager.application.service.ResolveCandidateService;
import com.iwhalecloud.citybrain.flow.platform.manager.application.service.SequentNodeCandidateConfigService;
import com.iwhalecloud.citybrain.flow.platform.manager.application.service.UserCustomFunctionService;
import com.iwhalecloud.citybrain.flow.platform.manager.application.utils.*;
import com.iwhalecloud.citybrain.flow.platform.manager.common.ConstanceVariable;
import com.iwhalecloud.citybrain.flow.platform.manager.domain.enums.NodeAuthEnum;
import com.iwhalecloud.citybrain.flow.platform.manager.domain.model.*;
import com.iwhalecloud.citybrain.flow.platform.manager.domain.model.model.FlowNodeCandidateControllerDomain;
import com.iwhalecloud.citybrain.flow.platform.manager.domain.model.task.BaseTaskVo;
import com.iwhalecloud.citybrain.flow.platform.manager.domain.model.task.SequentNodeCandidateConfigQueryVo;
import com.iwhalecloud.citybrain.flow.platform.manager.domain.model.userentity.CandidateEntity;
import com.iwhalecloud.citybrain.flow.platform.manager.domain.repository.*;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.collections4.MapUtils;
import org.apache.commons.lang3.StringUtils;
import org.flowable.bpmn.model.FlowElement;
import org.flowable.bpmn.model.FlowNode;
import org.flowable.bpmn.model.SequenceFlow;
import org.flowable.bpmn.model.UserTask;
import org.flowable.engine.ManagementService;
import org.flowable.engine.RepositoryService;
import org.flowable.engine.RuntimeService;
import org.flowable.engine.TaskService;
import org.flowable.engine.common.api.FlowableException;
import org.flowable.engine.impl.persistence.entity.ExecutionEntity;
import org.flowable.engine.repository.Model;
import org.flowable.engine.runtime.ProcessInstance;
import org.flowable.task.api.Task;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;

import java.nio.charset.StandardCharsets;
import java.util.*;
import java.util.stream.Collectors;

/**
 * @author: liyang
 * @date: 2021/12/11 9:47
 */
@Slf4j
@Service
public class SequentNodeCandidateConfigServiceImpl implements SequentNodeCandidateConfigService {


    @Value("${flow.paramReg:MANUAL_\\w*}")
    private String paramReg;
    private String expressionReg = "\\{(.*?)\\}";
    //    \$\{(.*?)\}
    @Autowired
    private TaskService taskService;

    @Autowired
    private RuntimeService runtimeService;

    @Autowired
    private FlowTaskCandidateSettingsRepository flowTaskCandidateSettingsRepository;

    @Autowired
    private RepositoryService repositoryService;

    @Autowired
    private ManagementService managementService;

    @Autowired
    private FlowNextNodeCandidateRepository flowNextNodeCandidateRepository;

    @Autowired
    private ResolveCandidateService resolveCandidateService;

    @Autowired
    private NodeCandidateService nodeCandidateService;

    @Autowired
    private FlowReModelCustomConfigRepository flowReModelCustomConfigRepository;

    @Autowired
    private FlowNodeCandidateControllerRepository flowNodeCandidateControllerRepository;

    @Autowired
    private UserCustomFunctionService userCustomFunctionService;

    @Autowired
    private FlowReNodeAuthRepository nodeAuthRepository;

    @Override
    public List<FlowSpecifyTheNodeHandlerTaskQueryInfo> getSequentNodeCandidateConfig(SequentNodeCandidateConfigQueryVo sequentNodeCandidateConfigQueryVo) {
        if (StringUtils.isBlank(sequentNodeCandidateConfigQueryVo.getTaskId())) {
            return null;
        }
        Task task = taskService.createTaskQuery().taskId(sequentNodeCandidateConfigQueryVo.getTaskId()).singleResult();
        if (Objects.isNull(task)) {
            return null;
        }

        //获取当前节点配置的需要强制选人的节点
        ProcessInstance processInstance = runtimeService.createProcessInstanceQuery().processInstanceId(task.getProcessInstanceId()).singleResult();
        String deployId = processInstance.getDeploymentId();

        List<FlowNodeCandidateControllerDomain> domainList = flowNodeCandidateControllerRepository.getFlowNodeCandidateController(deployId, task.getTaskDefinitionKey());

        Set<String> forcePickNodeSet = new LinkedHashSet<>();
        if (CollectionUtils.isNotEmpty(domainList)) {
            String controllNodes = domainList.get(0).getControlNodes();
            String[] controllNodeAry = controllNodes.split(",");
            for (String controllNode : controllNodeAry) {
                forcePickNodeSet.add(controllNode);
            }
        }

        //获取当前的执行
        String currentExecutionId = nodeCandidateService.getCurrentExecutionId(task);
        //获取当前所属的子流程实例
        ExecutionEntity executionEntity = nodeCandidateService.getSubProcessInstanceExecution(currentExecutionId);
        if (Objects.isNull(executionEntity)) {
            executionEntity = (ExecutionEntity) runtimeService.createExecutionQuery().executionId(processInstance.getProcessInstanceId()).singleResult();
        }

        if (MapUtils.isNotEmpty(sequentNodeCandidateConfigQueryVo.getVariables())) {
            Map<String, Object> variables = sequentNodeCandidateConfigQueryVo.getVariables();
            Iterator<Map.Entry<String, Object>> iterator = variables.entrySet().iterator();
            while (iterator.hasNext()) {
                Map.Entry<String, Object> entry = iterator.next();
                executionEntity.setTransientVariable(entry.getKey(), entry.getValue());
            }
        }
        Set<String> executableNode = new LinkedHashSet<>();

        // 节点是否是否忽略网关条件，返回后续所有强制选人节点
        List<FlowReNodeAuthVo> nodeAuthList = nodeAuthRepository.listNodeAuthByProcdefIdAndNodeCode(task.getProcessDefinitionId(), task.getTaskDefinitionKey());
        Map<String, Boolean> authMap = nodeAuthList.stream().collect(Collectors.toMap(FlowReNodeAuthVo::getAuthName, FlowReNodeAuthVo::getAuthSwitch));
        Boolean canRecall = authMap.getOrDefault(NodeAuthEnum.IGNORE_GATEWAY.getCode(), false);
        sequentNodeCandidateConfigQueryVo.setIgnoreGateway(canRecall);

        //如果配置的强制选人节点不为空，则默认取所有的数据
        //没有配置的话，默认只取孩子节点数据，孙子节点的数据不处理
        if (CollectionUtils.isNotEmpty(forcePickNodeSet)) {
            //先取出后续所有的节点，再跟配置的强制选人节点取交集
            Set<String> sequentExecutableNode = getExecutableNodeByTaskId(task, executionEntity, false, sequentNodeCandidateConfigQueryVo.isIgnoreGateway());
            if (sequentExecutableNode != null && sequentExecutableNode.size() > 0) {
                // 取交集并按照之前的流程的顺序
                Set<String> filterNodes = new LinkedHashSet<>();
                for (String nodeCode : sequentExecutableNode) {
                    if (forcePickNodeSet.contains(nodeCode)) {
                        filterNodes.add(nodeCode);
                    }
                }
                executableNode = filterNodes;
            }
        } else {
            executableNode = getExecutableNodeByTaskId(task, executionEntity, sequentNodeCandidateConfigQueryVo.isOnlyFirstLevelNodes(), sequentNodeCandidateConfigQueryVo.isIgnoreGateway());
        }

        List<FlowSpecifyTheNodeHandlerTaskQueryInfo> flowSpecifyTheNodeHandlerTaskQueryInfoList = new ArrayList<>();
        //所有应该返回的节点
        if (CollectionUtils.isNotEmpty(executableNode)) {

            Model model = repositoryService.createModelQuery().deploymentId(processInstance.getDeploymentId()).singleResult();
            String editorSource = new String(repositoryService.getModelEditorSource(model.getId()), StandardCharsets.UTF_8);
            ProcessModelVo processModel = JsonUtils.toObject(editorSource, ProcessModelVo.class);
            processModel = ModelUtils.getInstance().transformToViewModel(processModel);
            Map<String, Map<String, String>> map = processModel.getNodes().stream()
                    .filter(i -> i.getShape().equals("UserTask"))
                    .map(ModelNodeVo::getModel)
                    .map(i -> (Map<String, String>) i.getProperties())
                    .filter(i -> StringUtils.isNotEmpty(i.get("overrideid")))
                    .collect(Collectors.toMap(i -> i.get("overrideid"), i -> i));

            for (String nodeCode : executableNode) {
                Map<String, List<CandidateEntity>> candidateMap = getNodeCandidateConfig(deployId, nodeCode, executionEntity);
                FlowSpecifyTheNodeHandlerTaskQueryInfo flowSpecifyTheNodeHandlerTaskQueryInfo = buildNodeCandidateVo(candidateMap, nodeCode, processInstance, executionEntity.getId());
                flowSpecifyTheNodeHandlerTaskQueryInfo.setNodeDescription(map.get(nodeCode).get("description"));

                List<ModelCustomConfigDomain> modelCustomConfigDomainList = flowReModelCustomConfigRepository.listModelConfigByDeployIdAndType(deployId, nodeCode, ConstanceVariable.CANDIDATE_SET_NULL);
                if (CollectionUtils.isNotEmpty(modelCustomConfigDomainList)) {
                    flowSpecifyTheNodeHandlerTaskQueryInfo.setCandidateSetNull(modelCustomConfigDomainList.get(0).getConfig());
                }
                List<ModelCustomConfigDomain> autoGetLastCandidates = flowReModelCustomConfigRepository.listModelConfigByDeployIdAndType(deployId, nodeCode, ConstanceVariable.AUTO_GET_LAST_CANDIDATE);
                if (CollectionUtils.isNotEmpty(autoGetLastCandidates)) {
                    flowSpecifyTheNodeHandlerTaskQueryInfo.setIsAutoGetLastCandidate(autoGetLastCandidates.get(0).getConfig());
                }
                flowSpecifyTheNodeHandlerTaskQueryInfoList.add(flowSpecifyTheNodeHandlerTaskQueryInfo);
            }
        }
        return flowSpecifyTheNodeHandlerTaskQueryInfoList;
    }

    @Override
    public List<NextNodeWithGatewayParamKey> getNextNodeByGatewayKey(BaseTaskVo baseTaskVo) throws Exception {
        String taskId = baseTaskVo.getTaskId();
        if (StringUtils.isBlank(taskId)) {
            throw new Exception("任务实例id[taskId]不能为空");
        }
        Task task = taskService.createTaskQuery().taskId(taskId).singleResult();
        if (Objects.isNull(task)) {
            throw new Exception("根据任务实例id[" + taskId + "]查询任务失败");
        }

        String deployId = taskService.getVariable(taskId, ConstanceVariable.DEPLOYMENT_ID, String.class);
        String manualSelectNexeNode = "0";
        List<ModelCustomConfigDomain> manualSelectNexeNodeConfig = flowReModelCustomConfigRepository.listModelConfigByDeployIdAndType(deployId, task.getTaskDefinitionKey(), ConstanceVariable.MANUAL_SELECT_NEXT_NODE);
        if (CollectionUtils.isNotEmpty(manualSelectNexeNodeConfig)) {
            manualSelectNexeNode = manualSelectNexeNodeConfig.get(0).getConfig();
        }
//        if (Objects.equals("0",manualSelectNexeNode)){
//            throw new Exception("当前节点未配置手动选择后续节点，请在流程图中勾选配置");
//        }

        FlowElement flowElement = repositoryService.getBpmnModel(task.getProcessDefinitionId()).getFlowElement(task.getTaskDefinitionKey());

        List<NextNodeWithGatewayParamKey> nextNodeWithGatewayParamKeyList = new ArrayList<>();

        FlowGatewayTravller flowGatewayTravller = new FlowGatewayTravller(paramReg);
        flowGatewayTravller.travllToTargetNode(flowElement, nextNodeWithGatewayParamKeyList, null);

        return nextNodeWithGatewayParamKeyList;
    }

    private FlowSpecifyTheNodeHandlerTaskQueryInfo buildNodeCandidateVo(Map<String, List<CandidateEntity>> candidateMap, String nodeCode, ProcessInstance processInstance, String parentExecutionId) {
        List<FlowTaskCandidateDataTypeVo> flowTaskCandidateDataTypeVoList = convertMapToList(candidateMap, processInstance.getProcessInstanceId());
        FlowSpecifyTheNodeHandlerTaskQueryInfo flowSpecifyTheNodeHandlerTaskQueryInfo = new FlowSpecifyTheNodeHandlerTaskQueryInfo();
        if (CollectionUtils.isNotEmpty(flowTaskCandidateDataTypeVoList)) {
            flowSpecifyTheNodeHandlerTaskQueryInfo.setDataTypeList(flowTaskCandidateDataTypeVoList);
        }
        flowSpecifyTheNodeHandlerTaskQueryInfo.setNodeCode(nodeCode);
        FlowElement flowElement = repositoryService.getBpmnModel(processInstance.getProcessDefinitionId()).getFlowElement(nodeCode);
        flowSpecifyTheNodeHandlerTaskQueryInfo.setNodeName(flowElement.getName());

        flowSpecifyTheNodeHandlerTaskQueryInfo.setForcePick("0");

        List<ModelCustomConfig> modelCustomConfigList = flowReModelCustomConfigRepository.listModelCustomConfig(processInstance.getDeploymentId(), nodeCode, ConstanceVariable.FORCE_PICK);
        if (CollectionUtils.isNotEmpty(modelCustomConfigList)) {
            if (Objects.equals("1", modelCustomConfigList.get(0).getConfig())) {
                flowSpecifyTheNodeHandlerTaskQueryInfo.setForcePick("1");
            }
        }

        flowSpecifyTheNodeHandlerTaskQueryInfo.setIsPick("0");
        List<ModelNextNodeCandidateSettings> modelNextNodeCandidateSettings = flowNextNodeCandidateRepository.selectByProcessInstanceIdAndNodeCodeAndParentExecutionId(processInstance.getProcessInstanceId()
                , nodeCode, parentExecutionId);
        if (CollectionUtils.isNotEmpty(modelNextNodeCandidateSettings)) {
            flowSpecifyTheNodeHandlerTaskQueryInfo.setIsPick("1");
        }

        // 节点是否默认选中后选人设置,默认是0-不选;1-选中
        flowSpecifyTheNodeHandlerTaskQueryInfo.setIsChooseCandidateUser("0");
        List<ModelCustomConfigDomain> chooseCandidateUserSetting = flowReModelCustomConfigRepository.listModelConfigByDeployIdAndType(processInstance.getDeploymentId(), nodeCode, ConstanceVariable.CHOOSE_CANDIDATE_USER_SETTING);
        if (CollectionUtils.isNotEmpty(chooseCandidateUserSetting)) {
            flowSpecifyTheNodeHandlerTaskQueryInfo.setIsChooseCandidateUser(chooseCandidateUserSetting.get(0).getConfig());
        }

        List<ModelCustomConfigDomain> isRequiredCommentSettings = flowReModelCustomConfigRepository.listModelConfigByDeployIdAndType(processInstance.getDeploymentId(), nodeCode, ConstanceVariable.IS_REQUIRED_COMMENT);
        if (CollectionUtils.isNotEmpty(isRequiredCommentSettings)) {
            flowSpecifyTheNodeHandlerTaskQueryInfo.setIsRequiredComment(isRequiredCommentSettings.get(0).getConfig());
        }

        List<ModelCustomConfigDomain> mustExpressSettings = flowReModelCustomConfigRepository.listModelConfigByDeployIdAndType(processInstance.getDeploymentId(), nodeCode, ConstanceVariable.MUST_EXPRESS);
        if (CollectionUtils.isNotEmpty(mustExpressSettings)) {
            flowSpecifyTheNodeHandlerTaskQueryInfo.setMustExpress(mustExpressSettings.get(0).getConfig());
        }

        List<ModelCustomConfigDomain> requiredRollbackCommentSettings = flowReModelCustomConfigRepository.listModelConfigByDeployIdAndType(processInstance.getDeploymentId(), nodeCode, ConstanceVariable.REQUIRED_ROLLBACK_COMMENT);
        if (CollectionUtils.isNotEmpty(requiredRollbackCommentSettings)) {
            flowSpecifyTheNodeHandlerTaskQueryInfo.setRequiredRollbackComment(requiredRollbackCommentSettings.get(0).getConfig());
        }

        // 校验是否是会签节点
        Boolean isMultiTask = FlowUtils.getInstance().isMultiTaskActivity(processInstance.getProcessInstanceId(), nodeCode);
        // 会签节点
        if (isMultiTask) {
            flowSpecifyTheNodeHandlerTaskQueryInfo.setIsMultiTask(true);
        }
        return flowSpecifyTheNodeHandlerTaskQueryInfo;
    }

    public Set<String> getExecutableNodeByTaskId(Task task, ExecutionEntity executionEntity, boolean onlyFirstLevelNodes, boolean ignoreGateway) {

        ProcessInstance processInstance = runtimeService.createProcessInstanceQuery().processInstanceId(task.getProcessInstanceId()).singleResult();

        FlowElement flowElement = repositoryService.getBpmnModel(processInstance.getProcessDefinitionId()).getFlowElement(task.getTaskDefinitionKey());
        Set<String> executableNode = new LinkedHashSet<>();
        executableNode = getExecutableNode(executionEntity, flowElement, executableNode, onlyFirstLevelNodes, ignoreGateway);
        return executableNode;
    }

    private Set<String> getExecutableNode(ExecutionEntity executionEntity, FlowElement flowElement, Set<String> executableNode, boolean onlyFirstLevelNodes, boolean ignoreGateway) {
        if (Objects.nonNull(flowElement) && flowElement instanceof FlowNode) {
            FlowNode flowNode = (FlowNode) flowElement;
            List<SequenceFlow> sequenceFlowList = flowNode.getOutgoingFlows();
            if (CollectionUtils.isNotEmpty(sequenceFlowList)) {
                for (SequenceFlow sequenceFlow : sequenceFlowList) {
                    String expression = sequenceFlow.getConditionExpression();
                    if (StringUtils.isNotBlank(expression) && !ignoreGateway) {
                        ExpressionCmd expressionCmd = new ExpressionCmd(expression, executionEntity);
                        Object objValue = null;
                        try {
                            objValue = managementService.executeCommand(expressionCmd);
                        } catch (Exception e) {
                            log.error("getExpressionValue error: expression=" + expression, e);
                            continue;
                        }
                        if (objValue instanceof Boolean) {
                            boolean executable = (boolean) objValue;
                            if (executable) {
                                checkFLowNodeType(sequenceFlow.getTargetFlowElement(), executionEntity, executableNode, onlyFirstLevelNodes, ignoreGateway);
                            }
                        }
                    } else {
                        //如果表达式为空，则直接取目标节点
                        boolean shouldFollow = shouldContinueWithFlow(flowNode.getName(), sequenceFlow, executionEntity, ignoreGateway);
                        if (shouldFollow) {
                            checkFLowNodeType(sequenceFlow.getTargetFlowElement(), executionEntity, executableNode, onlyFirstLevelNodes, ignoreGateway);
                        } else {
                            continue;
                        }
                    }
                }
            }
        }
        return executableNode;
    }

    private boolean shouldContinueWithFlow(String fromNode, SequenceFlow sequenceFlow, ExecutionEntity executionEntity, boolean ignoreGateway) {
        String expression = sequenceFlow.getConditionExpression();
        // 表达式是空，非网关，应该直接继续走
        // 如果忽略网关路由条件，应该直接继续走
        if (StringUtils.isBlank(expression) || ignoreGateway) {
            return true;
        }

        // 网关，那么尝试判定在当前条件下是否要走
        ExpressionCmd expressionCmd = new ExpressionCmd(expression, executionEntity);
        Object objValue = null;
        try {
            objValue = managementService.executeCommand(expressionCmd);
        } catch (FlowableException ex) {
            String exMessage = ex.getMessage();
            // 条件不充分，无法判定下一个节点是否遍历，那么应该遍历
            if (exMessage != null && exMessage.contains("Unknown property used in expression")) {
                log.info("从节点 {} 出来的连线 {} 上的判定条件 {}，参数不充分，认为应该继续",
                        fromNode,
                        sequenceFlow.getName(), expressionCmd);
                return true;
            }
        } catch (Exception e) {
            log.error(
                    String.format("从节点 %s 出来的连线 %s 在评估表达式有其他的异常，getExpressionValue error: expression %s ", fromNode, sequenceFlow.getName(), expressionCmd),
                    e);
            return false;
        }
        return Boolean.TRUE.equals(objValue);
    }


    private void checkFLowNodeType(FlowElement flowElement, ExecutionEntity executionEntity, Set<String> executableNode, boolean onlyFirstLevelNodes, boolean ignoreGateway) {
        if (flowElement instanceof UserTask) {
            if (executableNode.contains(flowElement.getId())) {
                return;
            }
            executableNode.add(flowElement.getId());
            //如果不是获取第一层节点，即获取所有节点，则继续往下执行
            if (!onlyFirstLevelNodes) {
                getExecutableNode(executionEntity, flowElement, executableNode, onlyFirstLevelNodes, ignoreGateway);
            }
        } else {
            //排他网关、并行网关、包含网关的处理
            getExecutableNode(executionEntity, flowElement, executableNode, onlyFirstLevelNodes, ignoreGateway);
        }
    }


    private Map<String, List<CandidateEntity>> getNodeCandidateConfig(String deployId, String nodeCode, ExecutionEntity executionEntity) {


        Map<String, List<CandidateEntity>> candidateMap = new HashMap<>();
        List<ModelTaskCandidateSettings> taskCandidateSettingsList = flowTaskCandidateSettingsRepository.listModelTaskCandidateSettings(deployId, nodeCode);
        if (CollectionUtils.isNotEmpty(taskCandidateSettingsList)) {

            for (ModelTaskCandidateSettings modelTaskCandidateSettings : taskCandidateSettingsList) {
                if (modelTaskCandidateSettings.getDataType().equalsIgnoreCase("var")) {
                    try {
                        ExpressionCmd expressionCmd = new ExpressionCmd(modelTaskCandidateSettings.getCandidateValue(), executionEntity);
                        Object objValue = managementService.executeCommand(expressionCmd);
                        if (Objects.nonNull(objValue)) {
                            if (objValue instanceof String) {
                                String strValue = String.valueOf(objValue);
                                String[] str = strValue.split(",");
                                for (String s : str) {
                                    CandidateEntity candidateEntity = resolveCandidateService.getCandidateEntity(modelTaskCandidateSettings.getCandidateType(), s);
                                    addToCandidateMap(candidateEntity, candidateMap);
                                }
                            } else if (objValue instanceof List) {
                                List objValueList = (List) objValue;
                                for (Object obj : objValueList) {
                                    if (obj instanceof String) {
                                        String str = String.valueOf(obj);
                                        CandidateEntity candidateEntity = resolveCandidateService.getCandidateEntity(modelTaskCandidateSettings.getCandidateType(), str);
                                        addToCandidateMap(candidateEntity, candidateMap);
                                    }
                                }
                            }
                        }
                    } catch (Exception e) {
                        log.error("getValueFromExpress error:", e);
                    }
                } else {
                    CandidateEntity candidateEntity = new CandidateEntity();
                    candidateEntity.setType(modelTaskCandidateSettings.getCandidateType());
                    candidateEntity.setName(modelTaskCandidateSettings.getCandidateName());
                    candidateEntity.setCode(modelTaskCandidateSettings.getCandidateValue());
                    addToCandidateMap(candidateEntity, candidateMap);
                }
            }
        }
        return candidateMap;
    }

    private void addToCandidateMap(CandidateEntity candidateEntity, Map<String, List<CandidateEntity>> candidateMap) {
        if (Objects.nonNull(candidateEntity)) {
            List<CandidateEntity> flowTaskCandidateInfoVoList = candidateMap.get(candidateEntity.getType());
            if (CollectionUtils.isEmpty(flowTaskCandidateInfoVoList)) {
                flowTaskCandidateInfoVoList = new ArrayList<>();
                candidateMap.put(candidateEntity.getType(), flowTaskCandidateInfoVoList);
            }
            flowTaskCandidateInfoVoList.add(candidateEntity);
        }
    }

    private List<FlowTaskCandidateDataTypeVo> convertMapToList(Map<String, List<CandidateEntity>> candidateMap, String processInstanceId) {
        List<FlowTaskCandidateDataTypeVo> flowTaskCandidateDataTypeVoList = new ArrayList<>();
        if (MapUtils.isNotEmpty(candidateMap)) {
            Iterator<Map.Entry<String, List<CandidateEntity>>> iterator = candidateMap.entrySet().iterator();
            while (iterator.hasNext()) {
                Map.Entry<String, List<CandidateEntity>> entry = iterator.next();
                String key = entry.getKey();
                List<CandidateEntity> value = entry.getValue();
                FlowTaskCandidateDataTypeVo flowTaskCandidateDataTypeVo = new FlowTaskCandidateDataTypeVo();
                // 存储候选人信息
                List<CandidateEntity> candidateInfoVoList = new ArrayList<CandidateEntity>();
                // 数据类型是函数,则需要特殊处理
                if (Objects.equals("FUNCTION", key)) {
                    if (CollectionUtils.isNotEmpty(value)) {
                        for (CandidateEntity candidateEntity : value) {
                            try {
                                List<CustomFunctionVo> customFunctionVoList = userCustomFunctionService.getCustomFunctionByFunId(candidateEntity.getCode(), processInstanceId, null);
                                if (customFunctionVoList != null && customFunctionVoList.size() > 0) {
                                    for (CustomFunctionVo vo : customFunctionVoList) {
                                        CandidateEntity entity = new CandidateEntity();
                                        entity.setCode(vo.getUserId());
                                        entity.setName(vo.getName());
                                        entity.setOrgId(vo.getOrgId());
                                        entity.setOrgName(vo.getOrgName());
                                        entity.setType("STA");
                                        candidateInfoVoList.add(entity);
                                    }
                                }
                            } catch (Exception exception) {
                                log.error("调用自定义函数接口失败,失败原因：" + exception.getMessage());
                            }
                        }
                        flowTaskCandidateDataTypeVo.setDataType(key);
                        flowTaskCandidateDataTypeVo.setFlowTaskCandidateInfoVos(candidateInfoVoList);
                        flowTaskCandidateDataTypeVoList.add(flowTaskCandidateDataTypeVo);
                    }
                } else {
                    flowTaskCandidateDataTypeVo.setDataType(key);
                    flowTaskCandidateDataTypeVo.setFlowTaskCandidateInfoVos(value);
                    flowTaskCandidateDataTypeVoList.add(flowTaskCandidateDataTypeVo);
                }
            }
        }
        return flowTaskCandidateDataTypeVoList;
    }

    /**
     * 获取节点后所有的分支节点，同时返回网关线上的参数
     *
     * @param baseTaskVo
     * @return
     */
    @Override
    public List<NextNodeWithGatewayParamKey> getNextNodesByNodeId(BaseTaskVo baseTaskVo) throws Exception {
        String taskId = baseTaskVo.getTaskId();
        if (StringUtils.isBlank(taskId)) {
            throw new Exception("任务实例id[taskId]不能为空");
        }
        Task task = taskService.createTaskQuery().taskId(taskId).singleResult();
        if (Objects.isNull(task)) {
            throw new Exception("根据任务实例id[" + taskId + "]查询任务失败");
        }

        String deployId = taskService.getVariable(taskId, ConstanceVariable.DEPLOYMENT_ID, String.class);
        String manualSelectNexeNode = "0";
        //校验是否在节点配置了人工选择后续节点
        List<ModelCustomConfigDomain> manualSelectNexeNodeConfig = flowReModelCustomConfigRepository.listModelConfigByDeployIdAndType(deployId, task.getTaskDefinitionKey(), ConstanceVariable.MANUAL_SELECT_NEXT_NODE);
        if (CollectionUtils.isNotEmpty(manualSelectNexeNodeConfig)) {
            manualSelectNexeNode = manualSelectNexeNodeConfig.get(0).getConfig();
        }
//        if (Objects.equals("0",manualSelectNexeNode)){
//            throw new Exception("当前节点未配置手动选择后续节点，请在流程图中勾选配置");
//        }

        FlowElement flowElement = repositoryService.getBpmnModel(task.getProcessDefinitionId()).getFlowElement(task.getTaskDefinitionKey());

        List<NextNodeWithGatewayParamKey> nextNodeWithGatewayParamKeyList = new ArrayList<>();

        FlowGatewayTravller flowGatewayTravller = new FlowGatewayTravller(expressionReg);
        flowGatewayTravller.travllToTargetNode(flowElement, nextNodeWithGatewayParamKeyList, null);

        return nextNodeWithGatewayParamKeyList;
    }

}
